package com.jgp.workflow.utils;

import com.jgp.common.utils.JGPUtil;
import com.jgp.security.pojo.UserInfo;
import com.jgp.security.secmodel.SecInstitution;
import com.jgp.security.secmodel.SecRole;
import com.jgp.security.secmodel.SecUser;
import com.jgp.security.service.SecInstitutionService;
import com.jgp.security.service.SecRoleService;
import com.jgp.sys.ui.Pager;
import com.jgp.sys.utils.SpringContextUtil;
import com.jgp.workflow.exception.WorkflowException;
import com.jgp.workflow.pojo.*;
import com.jgp.workflow.service.ProcessService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 项目   jgp-cloud-parent
 * 作者   loufei
 * 时间   2018/12/4
 */
@Slf4j
public class ProcessUtil {
    /**
     * 启动流程
     *
     * @param tenantId      业务系统ID
     * @param defKey        流程定义key
     * @param businessKey   业务主键
     * @param jsonVariables 全局变量
     * @return
     * @throws WorkflowException
     */
    public static Map<String, Object> start(String userId, String tenantId, String defKey, String businessKey, String jsonVariables) throws WorkflowException {
        Map<String, Object> variables = new HashMap<>();
        if (StringUtils.isNotBlank(jsonVariables)) {
            variables = JGPUtil.jsonToMap(jsonVariables);
            if (Objects.isNull(variables)) {
                log.error("流程变量转换错误");
            }
        }
        return start(userId, tenantId, defKey, businessKey, variables);
    }
    
    /**
     * 启动流程
     *
     * @param tenantId    业务系统ID
     * @param defKey      流程定义key
     * @param businessKey 业务主键
     * @param variables   全局变量
     * @return
     * @throws WorkflowException
     */
    public static Map<String, Object> start(String userId, String tenantId, String defKey, String businessKey, Map<String, Object> variables) throws WorkflowException {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        return processService.start(userId, tenantId, defKey, businessKey, variables);
    }
    
    /**
     * 完成任务
     * 推进任务到下一个节点
     * 传递全局变量
     *
     * @param procId        流程实例Id
     * @param taskId        任务Id
     * @param remark        备注
     * @param jsonVariables 【全局】变量 作用域整个流程实例
     * @throws WorkflowException
     */
    public static void completeWithGlobalVariables(String userId, String procId, String taskId, String jsonVariables, String remark) throws WorkflowException {
        Map<String, Object> variables = new HashMap<>();
        if (StringUtils.isNotBlank(jsonVariables)) {
            variables = JGPUtil.jsonToMap(jsonVariables);
            if (Objects.isNull(variables)) {
                log.error("流程变量转换错误");
            }
        }
        completeWithGlobalVariables(userId, procId, taskId, variables, remark);
    }
    
    /**
     * 完成任务
     * 推进任务到下一个节点
     * 传递局部变量
     *
     * @param procId        流程实例Id
     * @param taskId        任务Id
     * @param remark        备注
     * @param jsonVariables 【局部】变量 作用域当前任务节点
     * @throws WorkflowException
     */
    public static void completeWithLocalVariables(String userId, String procId, String taskId, String jsonVariables, String remark) throws WorkflowException {
        Map<String, Object> variables = new HashMap<>();
        if (StringUtils.isNotBlank(jsonVariables)) {
            variables = JGPUtil.jsonToMap(jsonVariables);
            if (Objects.isNull(variables)) {
                log.error("流程变量转换错误");
            }
        }
        completeWithLocalVariables(userId, procId, taskId, variables, remark);
    }
    
    /**
     * 完成任务
     * 推进任务到下一个节点
     * 传递全局变量
     *
     * @param procId    流程实例Id
     * @param taskId    任务Id
     * @param remark    备注
     * @param variables 【全局】变量 作用域整个流程实例
     * @throws WorkflowException
     */
    public static void completeWithGlobalVariables(String userId, String procId, String taskId, Map<String, Object> variables, String remark) throws WorkflowException {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        processService.completeWithGlobalVariables(userId, procId, taskId, variables, remark);
    }
    
    /**
     * 完成任务
     * 推进任务到下一个节点
     * 传递局部变量
     *
     * @param procId    流程实例Id
     * @param taskId    任务Id
     * @param remark    备注
     * @param variables 【局部】变量 作用域当前任务节点
     * @throws WorkflowException
     */
    public static void completeWithLocalVariables(String userId, String procId, String taskId, Map<String, Object> variables, String remark) throws WorkflowException {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        processService.completeWithLocalVariables(userId, procId, taskId, variables, remark);
    }
    
    /**
     * 完成任务
     * 推进任务到下一个节点
     * 不传递变量
     *
     * @param procId 流程实例Id
     * @param taskId 任务Id
     * @param remark 备注
     * @throws WorkflowException
     */
    public static void complete(String userId, String procId, String taskId, String remark) throws WorkflowException {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        processService.complete(userId, procId, taskId, remark);
    }
    
    /**
     * 查询用户指定流程实例，指定任务定义的任务实例
     *
     * @param userId
     * @param procId
     * @param taskDefKey
     * @return
     */
    public static List<ViewProcessTask> queryActiveTasksByUserAndTaskDefKey(String userId, String procId, String taskDefKey) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        return processService.queryActiveTasksByUserAndTaskDefKey(userId, procId, taskDefKey);
    }
    
    /**
     * 查询指定角色、部门指定流程实例，指定任务定义的任务实例
     * 都指定则属于这些组内的所有任务 都会查出来
     *
     * @param roleIds
     * @param orgIds
     * @param procId
     * @param taskDefKey
     * @return
     */
    public static List<ViewProcessTask> queryActiveTasksByUserRoleOrOrgAndTaskDefKey(List<Long> roleIds, List<Long> orgIds, String procId,
                                                                                     String taskDefKey) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        return processService.queryActiveTasksByUserAndTaskDefKey(roleIds, orgIds, procId, taskDefKey);
    }
    
    /**
     * 获取任务节点最后处理人
     *
     * @param procId
     * @param taskId
     * @return
     */
    public static String getTaskLastAssignee(String procId, String taskId) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        return processService.getTaskLastAssignee(procId, taskId);
    }
    
    /**
     * 获取流程图中绑定的业务页面地址
     *
     * @param procId
     * @param taskId
     * @param userId
     * @param editFlag
     * @return
     */
    public static String getCustomForm(String procId, String taskId, String userId, Boolean editFlag) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        return processService.getCustomForm(procId, taskId, userId, editFlag);
    }
    
    /**
     * 回退到上一步
     *
     * @param userId
     * @param procId
     * @param taskId
     * @param remark
     */
    public static void back(String userId, String procId, String taskId, String remark) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        processService.backTarget(userId, procId, taskId, null, remark);
    }
    
    /**
     * 跳转节点并指定targetTaskKey节点的待审批人为历史中最近一次targetTaskKey节点的审批人
     *
     * @param userId
     * @param procId
     * @param targetTaskKey
     * @param remark
     */
    public static void backTarget(String userId, String procId, String taskId, String targetTaskKey, String remark) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        processService.backTarget(userId, procId, taskId, targetTaskKey, remark);
    }
    
    /**
     * 跳转节点并指定endTaskDefKey节点的带审批人
     * @param userId 操作人员ID
     * @param procId 流程实例ID
     * @param taskId 当前任务ID
     * @param targetTaskKey 目标任务定义ID
     * @param remark 备注
     * @param targetPersons 目标任务待处理人员信息
     *                      {@link TargetPerson} new TargetPerson(TargetPersonType type, String targetId)
     *                      type: {@link TargetPersonType} TargetPersonType.USER 人员,TargetPersonType.ROLE 角色,TargetPersonType.ORG  部门
     *                      targetId: 如果TargetPersonType.USER 则为人的ID，如果TargetPersonType.ROLE 则为角色ID
     */
    public static void backTargetAndSetCandidate(String userId, String procId, String taskId, String targetTaskKey, String remark,
                                  List<TargetPerson> targetPersons) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        processService.backTargetAndSetCandidate(userId, procId, taskId, targetTaskKey, remark, targetPersons);
    }
    
    /**
     * 查询制定任务位置的进行中的业务主键
     *
     * @param procDefKey 流程定义ID
     * @param taskDefKey 任务定义ID
     * @return
     */
    public static List<String> queryRunTimeBusinessKeyByTaskDefIdAndProcDefId(String procDefKey, String taskDefKey) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        return processService.queryRunTimeBusinessKeyByTaskDefIdAndProcDefId(procDefKey, taskDefKey);
    }
    
    /**
     * 签收
     *
     * @param userId
     * @param taskId
     * @param remark
     * @throws WorkflowException
     */
    public static void claim(String userId, String taskId, String remark) throws WorkflowException {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        processService.claim(userId, taskId, remark);
    }
    
    /**
     * 取消签收
     *
     * @param userId
     * @param taskId
     * @param remark
     * @throws WorkflowException
     */
    public static void unClaim(String userId, String taskId, String remark) throws WorkflowException {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        processService.unClaim(userId, taskId, remark);
    }
    
    /**
     * 查询指定代办任务
     *
     * @param taskId
     * @throws WorkflowException
     */
    public static ViewProcessTask queryNotHandledTaskByTaskId(String taskId) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        return processService.queryNotHandledTaskByTaskId(taskId);
    }
    
    /**
     * 查询指定用户申请但未传递的任务
     *
     * @param userId
     * @return
     */
    public static List<ViewProcessTask> queryApplyButNotPass(String userId, Pager pager) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        return processService.queryApplyButNotPass(userId, pager);
    }
    
    /**
     * 查询任务所有审批意见
     *
     * @param taskId
     * @return
     */
    public static List<TaskComment> queryTaskComments(String taskId) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        return processService.queryTaskComments(taskId);
    }
    
    /**
     * 查询任务最新审批意见
     *
     * @param taskId
     * @return
     */
    public static TaskComment queryLastTaskComment(String taskId) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        return processService.queryLastTaskComments(taskId);
    }
    
    
    /**
     * 查询指定流程实例指定任务定义最新审批意见
     *
     * @param procId
     * @param taskDefKey
     * @return
     */
    public static TaskComment queryLastTaskCommentByProcIdAndTaskDefkey(String procId, String taskDefKey) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        return processService.queryLastTaskCommentByProcIdAndTaskDefkey(procId, taskDefKey);
    }
    
    
    /**
     * 查询指定流程实例的指定任务定义下所有处理人
     *
     * @param procId
     * @param taskDefKey
     * @return
     */
    public static List<SecUser> queryTasksAssignee(String procId, String taskDefKey) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        return processService.queryTasksAssignees(procId, taskDefKey);
    }
    
    /**
     * 查询指定流程实例的指定任务定义下所有处理人
     *
     * @param procId
     * @param taskDefKeys
     * @return
     */
    public static List<SecUser> queryTasksAssignees(String procId, List<String> taskDefKeys) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        return processService.queryTasksAssignees(procId, taskDefKeys);
    }
    
    public static void removeProcIns(String procId, String reason) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        processService.removeProcIns(procId, reason);
    }
    
    /**
     * 根据业务ID 查询流程实例
     *
     * @param businessKeys
     * @return
     */
    public static List<ViewProcessIns> queryProcessIns(List<String> businessKeys) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        return processService.queryProcessIns(businessKeys);
    }
    
    public static ViewProcessIns queryOneProcessInsBySn(String sn) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        return processService.queryOneProcessInsBySn(sn);
    }
    
    public static List<String> transformGroups(UserInfo currentUser) {
        SecInstitutionService institutionService = SpringContextUtil.getBean(SecInstitutionService.class);
        SecRoleService roleService = SpringContextUtil.getBean(SecRoleService.class);
        List<SecRole> roles = new ArrayList<>();
        roles.addAll(currentUser.getRoles());
        List<SecInstitution> institutions = new ArrayList<>();
        institutions.addAll(currentUser.getInstitutions());
        institutions.addAll(institutionService.queryDown(institutions));
        roles.addAll(roleService.queryDown(roles));
        List<String> groups = new ArrayList<>();
        if (institutions.size() == 0 && roles.size() > 0) {
            roles.forEach(role -> {
                groups.add("ROLE:" + role.getId());
            });
        } else if (institutions.size() > 0 && roles.size() == 0) {
            institutions.forEach(institution -> {
                groups.add("ORG:" + institution.getId());
            });
        } else if (institutions.size() > 0 && roles.size() > 0) {
            institutions.forEach(institution -> {
                roles.forEach(role -> {
                    groups.add("ROLE:" + role.getId());
                    groups.add("ORG:" + institution.getId() + ",ROLE:" + role.getId());
                });
                groups.add("ORG:" + institution.getId());
            });
        }
        return groups.stream().distinct().collect(Collectors.toList());
    }
    
    public static List<String> specialInstitutions(UserInfo currentUser, String specialCode) {
        SecInstitutionService institutionService = SpringContextUtil.getBean(SecInstitutionService.class);
        List<SecInstitution> institutions = currentUser.getSInsAllMap().get(specialCode);
        if (Objects.nonNull(institutions) && institutions.size() > 0) {
            List<SecInstitution> all = institutionService.queryDown(institutions);
            List<SecInstitution> downs = all.stream().filter(institution -> StringUtils.isNotBlank(institution.getSpecialTypeCode()) && institution
                    .getSpecialTypeCode().equals(specialCode)).collect(Collectors.toList());
            institutions.addAll(downs);
            return institutions.stream().map(institution -> institution.getId().toString()).distinct().collect(Collectors.toList());
        } else {
            return null;
        }
    }
    
    /**
     * 获取当前活动任务
     *
     * @param procId
     * @return
     */
    public static List<ViewProcessTask> getActiveTask(String procId) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        return processService.getActiveTask(procId);
    }
    
    public static ViewProcessTask getTaskByProcIdAndTaskDefKey(String procId, String taskDefKey) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        return processService.getTaskByProcIdAndTaskDefKey(procId, taskDefKey);
    }
    
    /**
     * 获取当前活动任务 下面可能会执行的节点
     *
     * @param procId
     * @return
     */
    public static List<ViewTaskDefinition> getNextTaskDefinition(String procId) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        return processService.getNextTaskDefinition(procId);
    }
    
    /**
     * 设置任务执行人
     *
     * @param taskId
     * @param userId
     */
    public static void setAssignee(String taskId, String userId) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        processService.setAssignee(taskId, userId);
    }
    
    
    /**
     * 设置任务候选人
     *
     * @param taskId
     * @param userIds
     */
    public static void setCandidate(String taskId, String... userIds) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        processService.setCandidate(taskId, userIds);
    }
    
    /**
     * 把授权给某人
     *
     * @param taskId
     * @param owner    任务持有者
     * @param assignee 执行人
     */
    public static void grantTo(String taskId, String owner, String assignee) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        processService.grantTo(taskId, owner, assignee);
    }
    
    public static void addMultiInstanceExecution(String taskId, String... assignees) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        processService.addMultiInstanceExecution(taskId, Arrays.asList(assignees));
    }
    
    public static void makeTop(String procId) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        processService.makeTop(procId);
    }
    
    public static void makeUnTop(String procId) {
        ProcessService processService = SpringContextUtil.getBean(ProcessService.class);
        processService.makeUnTop(procId);
    }
}

